/* @flow */

import type Router from '../index'
import {History} from './base'
import {cleanPath} from '../util/path'
import {START} from '../util/route'
import {setupScroll, handleScroll} from '../util/scroll'
import {pushState, replaceState, supportsPushState} from '../util/push-state'

export class HTML5History extends History {
    constructor(router: Router, base: ?string) {
        super(router, base)

        const expectScroll = router.options.scrollBehavior
        const supportsScroll = supportsPushState && expectScroll

        if (supportsScroll) {
            setupScroll()
        }

        const initLocation = getLocation(this.base)
        window.addEventListener('popstate', e => {
            const current = this.current

            // Avoiding first `popstate` event dispatched in some browsers but first
            // history route not updated since async guard at the same time.
            const location = getLocation(this.base)
            if (this.current === START && location === initLocation) {
                return
            }

            this.transitionTo(location, route => {
                if (supportsScroll) {
                    handleScroll(router, route, current, true)
                }
            })
        })
    }

    go(n: number) {
        window.history.go(n)
    }

    push(location: RawLocation, onComplete?: Function, onAbort?: Function) {
        const {current: fromRoute} = this
        this.transitionTo(location, route => {
            pushState(cleanPath(this.base + route.fullPath))
            handleScroll(this.router, route, fromRoute, false)
            onComplete && onComplete(route)
        }, onAbort)
    }

    replace(location: RawLocation, onComplete?: Function, onAbort?: Function) {
        const {current: fromRoute} = this
        this.transitionTo(location, route => {
            replaceState(cleanPath(this.base + route.fullPath))
            handleScroll(this.router, route, fromRoute, false)
            onComplete && onComplete(route)
        }, onAbort)
    }

    ensureURL(push?: boolean) {
        if (getLocation(this.base) !== this.current.fullPath) {
            const current = cleanPath(this.base + this.current.fullPath)
            push ? pushState(current) : replaceState(current)
        }
    }

    getCurrentLocation(): string {
        return getLocation(this.base)
    }
}

//浏览器中会存在当前访问的网址信息，该方法用于根据这个网址信息获得完整的url字符串
//信息，该方法的参数base的含义可查看history-->base.js中的base属性的含义以及官方文档
export function getLocation(base: string): string {
    //pathname指向端口号之后查询字符串之前的字符串，
    //示例：
    //'http://www.baidu.com/hello/world?name=james#1'
    //则pathname为'/hello/world'
    let path = window.location.pathname
    if (base && path.indexOf(base) === 0) { //base必须在path的开头
        //从path中删除base字符串
        path = path.slice(base.length)
    }
    //对于上例来说：
    //search为：'?name=james'
    //hash为：'#1'
    return (path || '/') + window.location.search + window.location.hash
}
